﻿#include <glm/gtc/type_ptr.hpp>

#include "InstrumentLabels.h"

constexpr double PI = 3.14159265358979323846;

_InstrumentLabel::_InstrumentLabel(
	FT_Face& font,
	int frame_size_x, int frame_size_y,
	size_t instruments_total_num,
	size_t instrument_index,
	std::string name,
	Color color,
	uint8_t alpha,
	uint32_t font_size,
	float line_spacing,
	GLuint glsl
) {
	auto codepoints = _utf8_to_codepoints(name);
	Location text_size = _calculate_text_size(font, name);
	int radius = round((std::min(frame_size_x, frame_size_y) - sqrt(text_size.x * text_size.x + text_size.y * text_size.y) / 2) / 2);
	double angle = (instrument_index + 0.5) / (double)instruments_total_num * 2 * PI;
	double _x = frame_size_x / 2 + cos(angle) * radius;
	double _y = frame_size_y / 2 - sin(angle) * radius;
	Text text = Drawer::initText(font, color, alpha, frame_size_x, frame_size_y, _x, _y, Anchor::CENTER, 0, 0, true, line_spacing, TextAlignment::CENTER, glsl);
	glGenFramebuffers(1, &_text.fbo);
	glBindFramebuffer(GL_FRAMEBUFFER, _text.fbo);

	// 创建纹理附件
	glGenTextures(1, &_text.texture);
	glBindTexture(GL_TEXTURE_2D, _text.texture);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, frame_size_x, frame_size_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _text.texture, 0);

	if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
		throw "";
	}
	Drawer::drawText(text, name, _text.fbo, _text.texture);
}

_Text _InstrumentLabel::get_frame() {
	return _text;
}

Location _InstrumentLabel::_calculate_text_size(FT_Face& font, std::string name) {
	int lineHeight = font->size->metrics.height >> 6;
	auto codepoints = _utf8_to_codepoints(name);

	int width = 0, max_height = 0;
	FT_UInt prev_glyph = 0;
	for (uint32_t cp : codepoints) {
		FT_Load_Char(font, cp, FT_LOAD_DEFAULT);
		FT_Render_Glyph(font->glyph, FT_RENDER_MODE_NORMAL);

		// 计算字间距（kerning）
		if (prev_glyph) {
			FT_Vector delta;
			FT_Get_Kerning(font, prev_glyph, font->glyph->glyph_index, FT_KERNING_DEFAULT, &delta);
			width += delta.x >> 6;
		}
		prev_glyph = font->glyph->glyph_index;

		width += font->glyph->advance.x >> 6;
		max_height = std::max<int>(max_height, static_cast<int>(font->glyph->metrics.height >> 6));
	}
	return Location{ width, max_height };
}

std::vector<uint32_t> _InstrumentLabel::_utf8_to_codepoints(const std::string str) {
	std::vector<uint32_t> codepoints;
	for (size_t i = 0; i < str.size();) {
		uint32_t codepoint = 0;
		if ((str[i] & 0x80) == 0x00) {        // 1字节
			codepoint = str[i++];
		}
		else if ((str[i] & 0xE0) == 0xC0) {  // 2字节
			codepoint = ((str[i++] & 0x1F) << 6) | (str[i++] & 0x3F);
		}
		else if ((str[i] & 0xF0) == 0xE0) {  // 3字节
			codepoint = ((str[i++] & 0x0F) << 12) | ((str[i++] & 0x3F) << 6) | (str[i++] & 0x3F);
		}
		else if ((str[i] & 0xF8) == 0xF0) {  // 4字节
			codepoint = ((str[i++] & 0x07) << 18) | ((str[i++] & 0x3F) << 12) | ((str[i++] & 0x3F) << 6) | (str[i++] & 0x3F);
		}
		codepoints.push_back(codepoint);
	}
	return codepoints;
}

_Text _InstrumentLabel::drawText(uint8_t* text_bitmap, int frame_size_x, int frame_size_y, GLuint shader_program) {
	_Text result;

	// 创建FBO
	glGenFramebuffers(1, &result.fbo);
	glBindFramebuffer(GL_FRAMEBUFFER, result.fbo);

	// 创建纹理附件
	glGenTextures(1, &result.texture);
	glBindTexture(GL_TEXTURE_2D, result.texture);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, frame_size_x, frame_size_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, result.texture, 0);

	if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
		throw "";
	}

	// 设置视口和投影
	glViewport(0, 0, frame_size_x, frame_size_y);
	glm::mat4 projection = glm::ortho(0.0f, static_cast<float>(frame_size_x), static_cast<float>(frame_size_y), 0.0f, -1.0f, 1.0f);

	// 清空FBO为透明
	Utils::clearFrame(result.fbo);

	// 创建临时纹理上传位图数据
	GLuint temp_texture;
	glGenTextures(1, &temp_texture);
	glBindTexture(GL_TEXTURE_2D, temp_texture);
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // 处理行对齐
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, frame_size_x, frame_size_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, text_bitmap);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 恢复默认

	// 准备顶点数据
	float x = 0;
	float y = 0;
	float w = frame_size_x;
	float h = frame_size_y;
	float vertices[] = {
		// 位置          // 纹理坐标（Y翻转）
		x,     y,      0.0f, 1.0f,
		x + w, y,      1.0f, 1.0f,
		x,     y + h,  0.0f, 0.0f,
		x,     y + h,  0.0f, 0.0f,
		x + w, y,      1.0f, 1.0f,
		x + w, y + h,  1.0f, 0.0f
	};

	// 创建VAO/VBO
	GLuint VAO, VBO;
	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);
	glBindVertexArray(VAO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	// 位置属性
	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
	// 纹理坐标属性
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
	glEnableVertexAttribArray(1);

	// 渲染设置
	glUseProgram(shader_program);
	GLint proj_loc = glGetUniformLocation(shader_program, "projection");
	glUniformMatrix4fv(proj_loc, 1, GL_FALSE, &projection[0][0]);

	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, temp_texture);
	GLint tex_loc = glGetUniformLocation(shader_program, "textureBitmap");
	glUniform1i(tex_loc, 0);

	// 绘制
	glBindVertexArray(VAO);
	glDrawArrays(GL_TRIANGLES, 0, 6);

	// 清理资源
	glDeleteVertexArrays(1, &VAO);
	glDeleteBuffers(1, &VBO);
	glDeleteTextures(1, &temp_texture);
	glBindTexture(GL_TEXTURE_2D, 0);
	glBindFramebuffer(GL_FRAMEBUFFER, 0);

	return result;
}

InstrumentLabels::InstrumentLabels(
	int frame_size_x, int frame_size_y,
	double frame_rate,
	std::vector<VelocityStream>& streams,
	uint32_t font_size,
	std::string font_path,
	int32_t font_index,
	float line_spacing,
	Color color,
	uint8_t alpha,
	FT_Library font_library
) :MLObj(frame_size_x, frame_size_y, frame_rate) {
	FT_Face _font;
	if (FT_New_Face(font_library, font_path.c_str(), font_index, &_font)) {
		throw "加载字体失败。";
	}
	if (FT_Set_Pixel_Sizes(_font, font_size, font_size)) {
		throw "设置字体大小失败。";
	}
	GLuint glsl = Utils::activateShader("./GLSL/TextVertex.glsl", "./GLSL/TextFragment.glsl");
	_mix_glsl = Utils::activateShader("./GLSL/MixVertex.glsl", "./GLSL/MixFragment.glsl");
	size_t instrument_total_num = streams.size();
	_frame = MLFrame(frame_size_x, frame_size_y);
	for (size_t i = 0; i < instrument_total_num; i++) {
		_InstrumentLabel label(
			_font,
			frame_size_x, frame_size_y,
			instrument_total_num,
			i,
			streams[i].name,
			color,
			alpha,
			font_size,
			line_spacing,
			glsl
		);
		_Text new_frame = label.get_frame();
		_frame.mix(new_frame.fbo, new_frame.texture, 0, _mix_glsl);
	}
	FT_Done_Face(_font);
}

void InstrumentLabels::get_frame(size_t frame_index, MLFrame& frame) {
	frame.mix(_frame, _mix_glsl);
}
